package org.budo.graph.druid.filter.connection;

import java.sql.SQLException;
import java.util.List;

import org.budo.support.slf4j.Slf4j;
import org.slf4j.Logger;

import com.alibaba.druid.filter.FilterChain;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidPooledConnection;
import com.alibaba.druid.proxy.jdbc.ConnectionProxy;
import com.alibaba.druid.proxy.jdbc.PreparedStatementProxy;
import com.alibaba.druid.proxy.jdbc.ResultSetProxy;
import com.alibaba.druid.proxy.jdbc.StatementProxy;

/**
 * 需要手动配置或加入到 DefaultDruidFilters
 * 
 * @author limingwei
 * @see com.alibaba.druid.support.profile.ProfileEntry
 * @see com.alibaba.druid.pool.DruidDataSource#getConnectionDirect(long)
 * @see com.alibaba.druid.support.http.StatViewServlet
 * @see com.alibaba.druid.support.http.StatViewServlet#process(String)
 * @see com.alibaba.druid.stat.DruidStatService#service(String)
 * @see com.alibaba.druid.support.http.stat.WebAppStatManager#getURIStatData(String)
 */
public class ActiveConnectionFilter extends AbstractActiveConnectionFilter {
    private static final Logger log = Slf4j.getLogger();

    private static ActiveConnectionFilter instance = null;

    /**
     * 缓存当前实例为静态变量
     */
    public ActiveConnectionFilter() {
        instance = this;
    }

    /**
     * 获取运行中的实例
     */
    public static ActiveConnectionFilter getInstance() {
        return instance;
    }

    /**
     * 获取数据库连接
     */
    public DruidPooledConnection dataSource_getConnection(FilterChain chain, DruidDataSource dataSource, long maxWaitMillis) throws SQLException {
        DruidPooledConnection connection = super.dataSource_getConnection(chain, dataSource, maxWaitMillis); // DruidPooledConnection 与下面的值是同一个

        try {
            List<Object> profilerList = ActiveConnectionFilterUtil.getCurrentProfilerList();

            this.putActiveConnection(connection, profilerList); // 把新的数据,旧的数据都带上,解析数据时就要注意
        } catch (Throwable e) {
            log.error("put activeConnections error, " + e, e);
        }

        return connection;
    }

    /**
     * 归还数据库连接
     */
    public void dataSource_releaseConnection(FilterChain chain, DruidPooledConnection connection) throws SQLException {
        try {
            this.removeActiveConnection(connection);
        } catch (Throwable e) {
            log.error("remove activeConnections error, " + e, e);
        }

        super.dataSource_releaseConnection(chain, connection);
    }

    public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection, String sql) throws SQLException {
        ActiveConnectionProfiler.enter("connection_prepareStatement_1:" + sql); // 添加一行记录
        return super.connection_prepareStatement(chain, connection, sql);
    }

    public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection, String sql, int autoGeneratedKeys) throws SQLException {
        ActiveConnectionProfiler.enter("connection_prepareStatement_2:" + sql); // 添加一行记录
        return super.connection_prepareStatement(chain, connection, sql, autoGeneratedKeys);
    }

    public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection, String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
        ActiveConnectionProfiler.enter("connection_prepareStatement_3:" + sql); // 添加一行记录
        return super.connection_prepareStatement(chain, connection, sql, resultSetType, resultSetConcurrency);
    }

    public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection, String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
        ActiveConnectionProfiler.enter("connection_prepareStatement_4:" + sql); // 添加一行记录
        return super.connection_prepareStatement(chain, connection, sql, resultSetType, resultSetConcurrency, resultSetHoldability);
    }

    public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection, String sql, int[] columnIndexes) throws SQLException {
        ActiveConnectionProfiler.enter("connection_prepareStatement_5:" + sql); // 添加一行记录
        return super.connection_prepareStatement(chain, connection, sql, columnIndexes);
    }

    public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection, String sql, String[] columnNames) throws SQLException {
        ActiveConnectionProfiler.enter("connection_prepareStatement_6:" + sql); // 添加一行记录
        return super.connection_prepareStatement(chain, connection, sql, columnNames);
    }

    /**
     * @see com.alibaba.druid.filter.stat.StatFilter#internalBeforeStatementExecute(StatementProxy, String)
     */
    public boolean preparedStatement_execute(FilterChain chain, PreparedStatementProxy statement) throws SQLException {
        return super.preparedStatement_execute(chain, statement);
    }

    public ResultSetProxy preparedStatement_executeQuery(FilterChain chain, PreparedStatementProxy statement) throws SQLException {
        return super.preparedStatement_executeQuery(chain, statement);
    }

    public int preparedStatement_executeUpdate(FilterChain chain, PreparedStatementProxy statement) throws SQLException {
        return super.preparedStatement_executeUpdate(chain, statement);
    }

    public int[] statement_executeBatch(FilterChain chain, StatementProxy statement) throws SQLException {
        return super.statement_executeBatch(chain, statement);
    }

    public boolean statement_execute(FilterChain chain, StatementProxy statement, String sql) throws SQLException {
        return super.statement_execute(chain, statement, sql);
    }

    public boolean statement_execute(FilterChain chain, StatementProxy statement, String sql, int autoGeneratedKeys) throws SQLException {
        return super.statement_execute(chain, statement, sql, autoGeneratedKeys);
    }

    public boolean statement_execute(FilterChain chain, StatementProxy statement, String sql, int[] columnIndexes) throws SQLException {
        return super.statement_execute(chain, statement, sql, columnIndexes);
    }

    public boolean statement_execute(FilterChain chain, StatementProxy statement, String sql, String[] columnNames) throws SQLException {
        return super.statement_execute(chain, statement, sql, columnNames);
    }

    public ResultSetProxy statement_executeQuery(FilterChain chain, StatementProxy statement, String sql) throws SQLException {
        return super.statement_executeQuery(chain, statement, sql);
    }

    public int statement_executeUpdate(FilterChain chain, StatementProxy statement, String sql) throws SQLException {
        return super.statement_executeUpdate(chain, statement, sql);
    }

    public int statement_executeUpdate(FilterChain chain, StatementProxy statement, String sql, int autoGeneratedKeys) throws SQLException {
        return super.statement_executeUpdate(chain, statement, sql, autoGeneratedKeys);
    }

    public int statement_executeUpdate(FilterChain chain, StatementProxy statement, String sql, int[] columnIndexes) throws SQLException {
        return super.statement_executeUpdate(chain, statement, sql, columnIndexes);
    }

    public int statement_executeUpdate(FilterChain chain, StatementProxy statement, String sql, String[] columnNames) throws SQLException {
        return super.statement_executeUpdate(chain, statement, sql, columnNames);
    }
}